﻿using System;
using System.Collections.Generic;

namespace AladdinGameFramework.ObjectPool
{
	/// <summary>
	/// 对象池管理器。
	/// </summary>
	internal sealed partial class ObjectPoolManager : GameFrameworkModule, IObjectPoolManager
	{
		private const int DefaultCapacity = int.MaxValue;
		private const float DefaultExpireTime = float.MaxValue;
		private const int DefaultPriority = 0;

		private readonly Dictionary<string, ObjectPoolBase> m_ObjectPools;

		/// <summary>
		/// 初始化对象池管理器的新实例。
		/// </summary>
		public ObjectPoolManager()
		{
			m_ObjectPools = new Dictionary<string, ObjectPoolBase>();
		}

		/// <summary>
		/// 获取游戏框架模块优先级。
		/// </summary>
		/// <remarks>优先级较高的模块会优先轮询，并且关闭操作会后进行。</remarks>
		internal override int Priority
		{
			get
			{
				return 90;
			}
		}

		/// <summary>
		/// 获取对象池数量。
		/// </summary>
		public int Count
		{
			get
			{
				return m_ObjectPools.Count;
			}
		}

		/// <summary>
		/// 对象池管理器轮询。
		/// </summary>
		/// <param name="elapseSeconds">逻辑流逝时间，以秒为单位。</param>
		/// <param name="realElapseSeconds">真实流逝时间，以秒为单位。</param>
		internal override void Update(float elapseSeconds, float realElapseSeconds)
		{
			foreach (KeyValuePair<string, ObjectPoolBase> objectPool in m_ObjectPools)
			{
				objectPool.Value.Update(elapseSeconds, realElapseSeconds);
			}
		}

		/// <summary>
		/// 关闭并清理对象池管理器。
		/// </summary>
		internal override void Shutdown()
		{
			foreach (KeyValuePair<string, ObjectPoolBase> objectPool in m_ObjectPools)
			{
				objectPool.Value.Shutdown();
			}

			m_ObjectPools.Clear();
		}

		/// <summary>
		/// 检查是否存在对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <returns>是否存在对象池。</returns>
		public bool HasObjectPool<T>() where T : ObjectBase
		{
			return HasObjectPool<T>(string.Empty);
		}

		/// <summary>
		/// 检查是否存在对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <returns>是否存在对象池。</returns>
		public bool HasObjectPool<T>(string name) where T : ObjectBase
		{
			return m_ObjectPools.ContainsKey(Utility.Text.GetFullName<T>(name));
		}

		/// <summary>
		/// 获取对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <returns>要获取的对象池。</returns>
		public IObjectPool<T> GetObjectPool<T>() where T : ObjectBase
		{
			return GetObjectPool<T>(string.Empty);
		}

		/// <summary>
		/// 获取对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <returns>要获取的对象池。</returns>
		public IObjectPool<T> GetObjectPool<T>(string name) where T : ObjectBase
		{
			ObjectPoolBase objectPool = null;
			if (m_ObjectPools.TryGetValue(Utility.Text.GetFullName<T>(name), out objectPool))
			{
				return (IObjectPool<T>)objectPool;
			}

			return null;
		}

		/// <summary>
		/// 获取所有对象池。
		/// </summary>
		/// <returns>所有对象池。</returns>
		public ObjectPoolBase[] GetAllObjectPools()
		{
			return GetAllObjectPools(false);
		}

		/// <summary>
		/// 获取所有对象池。
		/// </summary>
		/// <param name="sort">是否根据对象池的优先级排序。</param>
		/// <returns>所有对象池。</returns>
		public ObjectPoolBase[] GetAllObjectPools(bool sort)
		{
			if (sort)
			{
				List<ObjectPoolBase> objectPools = new List<ObjectPoolBase>(m_ObjectPools.Values);
				objectPools.Sort(ObjectPoolComparer);
				return objectPools.ToArray();
			}
			else
			{
				int index = 0;
				ObjectPoolBase[] objectPools = new ObjectPoolBase[m_ObjectPools.Count];
				foreach (KeyValuePair<string, ObjectPoolBase> objectPool in m_ObjectPools)
				{
					objectPools[index++] = objectPool.Value;
				}

				return objectPools;
			}
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>() where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, false, DefaultCapacity, DefaultExpireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, false, DefaultCapacity, DefaultExpireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="capacity">对象池的容量。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(int capacity) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, false, capacity, DefaultExpireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(float expireTime) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, false, DefaultCapacity, expireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="capacity">对象池的容量。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, int capacity) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, false, capacity, DefaultExpireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, float expireTime) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, false, DefaultCapacity, expireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(int capacity, float expireTime) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, false, capacity, expireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(int capacity, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, false, capacity, DefaultExpireTime, priority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(float expireTime, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, false, DefaultCapacity, expireTime, priority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, int capacity, float expireTime) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, false, capacity, expireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, int capacity, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, false, capacity, DefaultExpireTime, priority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, float expireTime, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, false, DefaultCapacity, expireTime, priority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(int capacity, float expireTime, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, false, capacity, expireTime, priority);
		}

		/// <summary>
		/// 创建允许单次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许单次获取的对象池。</returns>
		public IObjectPool<T> CreateSingleSpawnObjectPool<T>(string name, int capacity, float expireTime, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, false, capacity, expireTime, priority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>() where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, true, DefaultCapacity, DefaultExpireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, true, DefaultCapacity, DefaultExpireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="capacity">对象池的容量。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(int capacity) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, true, capacity, DefaultExpireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(float expireTime) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, true, DefaultCapacity, expireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="capacity">对象池的容量。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, int capacity) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, true, capacity, DefaultExpireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, float expireTime) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, true, DefaultCapacity, expireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(int capacity, float expireTime) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, true, capacity, expireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(int capacity, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, true, capacity, DefaultExpireTime, priority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(float expireTime, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, true, DefaultCapacity, expireTime, priority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, int capacity, float expireTime) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, true, capacity, expireTime, DefaultPriority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, int capacity, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, true, capacity, DefaultExpireTime, priority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, float expireTime, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, true, DefaultCapacity, expireTime, priority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(int capacity, float expireTime, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(string.Empty, true, capacity, expireTime, priority);
		}

		/// <summary>
		/// 创建允许多次获取的对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">对象池名称。</param>
		/// <param name="capacity">对象池的容量。</param>
		/// <param name="expireTime">对象池对象过期秒数。</param>
		/// <param name="priority">对象池的优先级。</param>
		/// <returns>要创建的允许多次获取的对象池。</returns>
		public IObjectPool<T> CreateMultiSpawnObjectPool<T>(string name, int capacity, float expireTime, int priority) where T : ObjectBase
		{
			return CreateObjectPool<T>(name, true, capacity, expireTime, priority);
		}

		/// <summary>
		/// 销毁对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <returns>是否销毁对象池成功。</returns>
		public bool DestroyObjectPool<T>() where T : ObjectBase
		{
			return DestroyObjectPool<T>(string.Empty);
		}

		/// <summary>
		/// 销毁对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="name">要销毁的对象池名称。</param>
		/// <returns>是否销毁对象池成功。</returns>
		public bool DestroyObjectPool<T>(string name) where T : ObjectBase
		{
			string fullName = Utility.Text.GetFullName<T>(name);
			ObjectPoolBase objectPool = null;
			if (m_ObjectPools.TryGetValue(fullName, out objectPool))
			{
				objectPool.Shutdown();
				return m_ObjectPools.Remove(fullName);
			}

			return false;
		}

		/// <summary>
		/// 销毁对象池。
		/// </summary>
		/// <typeparam name="T">对象类型。</typeparam>
		/// <param name="objectPool">要销毁的对象池。</param>
		/// <returns>是否销毁对象池成功。</returns>
		public bool DestroyObjectPool<T>(IObjectPool<T> objectPool) where T : ObjectBase
		{
			if (objectPool == null)
			{
				throw new GameFrameworkException("Object pool is invalid.");
			}

			return DestroyObjectPool<T>(objectPool.Name);
		}

		/// <summary>
		/// 释放对象池中的可释放对象。
		/// </summary>
		public void Release()
		{
			ObjectPoolBase[] objectPools = GetAllObjectPools(true);
			foreach (ObjectPoolBase objectPool in objectPools)
			{
				objectPool.Release();
			}
		}

		/// <summary>
		/// 释放对象池中的所有未使用对象。
		/// </summary>
		public void ReleaseAllUnused()
		{
			ObjectPoolBase[] objectPools = GetAllObjectPools(true);
			foreach (ObjectPoolBase objectPool in objectPools)
			{
				objectPool.ReleaseAllUnused();
			}
		}

		private IObjectPool<T> CreateObjectPool<T>(string name, bool allowMultiSpawn, int capacity, float expireTime, int priority) where T : ObjectBase
		{
			if (HasObjectPool<T>(name))
			{
				throw new GameFrameworkException(string.Format("Already exist object pool '{0}'.", Utility.Text.GetFullName<T>(name)));
			}

			ObjectPool<T> objectPool = new ObjectPool<T>(name, allowMultiSpawn, capacity, expireTime, priority);
			m_ObjectPools.Add(Utility.Text.GetFullName<T>(name), objectPool);
			return objectPool;
		}

		private int ObjectPoolComparer(ObjectPoolBase a, ObjectPoolBase b)
		{
			return a.Priority.CompareTo(b.Priority);
		}
	}
}
